package cn.baage.campus.controller;

import cn.baage.campus.config.properties.BaageProperties;
import cn.baage.campus.constant.BaageConstant;
import cn.baage.campus.constant.CacheConstant;
import cn.baage.campus.constant.validation.AddGroup;
import cn.baage.campus.enums.ExceptionType;
import cn.baage.campus.exception.BizException;
import cn.baage.campus.model.vo.ForgetReqVO;
import cn.baage.campus.model.vo.UserBaseSaveReqVO;
import cn.baage.campus.model.po.User;
import cn.baage.campus.model.vo.UserLoginReqVO;
import cn.baage.campus.service.AuthService;
import cn.baage.campus.service.RedisService;
import cn.baage.campus.service.UserService;
import cn.baage.campus.utils.CodeUtils;
import cn.baage.campus.utils.MailUtils;
import cn.baage.campus.utils.Result;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.google.code.kaptcha.impl.DefaultKaptcha;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.util.FastByteArrayOutputStream;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * @Description: 认证API
 * @Author: 八阿哥
 * @url: baage.cn
 * @Version: 1.0
 **/
@RestController
@RequestMapping("/auth")
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Api(tags = "登录认证接口")
@Slf4j
public class AuthController {

    private final AuthService authService;
    private final UserService userService;
    private final DefaultKaptcha captchaProducerMath;
    private final RedisService<String> redisService;
    private final MailUtils mailUtils;
    private final BaageProperties baageProperties;


    @ApiOperation(value = "账号密码登录")
    @PostMapping("/login")
    public Result<Map<String, String>> login(@RequestBody UserLoginReqVO userLoginReqVO) {
        if (StrUtil.isBlank(userLoginReqVO.getUsername()) || StrUtil.isBlank(userLoginReqVO.getPassword())) {
            throw new BizException(ExceptionType.PARAM_NOT_VALID);
        }
        if (baageProperties.getCaptcha()) {
            this.checkCaptcha(userLoginReqVO.getUuid(), userLoginReqVO.getCaptcha());
        }
        Map<String, String>  result = authService.loginByUserName(userLoginReqVO.getUsername(), userLoginReqVO.getPassword());
        return Result.success(result);
    }


    @ApiOperation(value = "微信登录")
    @PostMapping("/wxLogin")
    public Result<Map<String, String>> wxLogin(@RequestParam String code) {
        String url  = "https://api.weixin.qq.com/sns/jscode2session";
        Map<String, Object> params = new HashMap<String, Object>() {{
            put("appid", baageProperties.getWxAppId());
            put("js_code", baageProperties.getWxAppSecret());
            put("grant_type", "authorization_code");
        }};
        String res = HttpUtil.get(url,params);
        JSONObject jsonObject = JSON.parseObject(res);
        String openid = (String) jsonObject.get("openid");
        if (StrUtil.isEmpty(openid)) {
            return Result.fail(ExceptionType.WX_OPENID_ERROR.getErrorMessage());
        }
        Map<String, String> result = authService.loginByWx(openid);
        return Result.success(result);

    }


    @ApiOperation(value = "退出登录")
    @GetMapping("/logout")
    public Result<Object> logout() {
        authService.logout();
        return Result.success();
    }


    @ApiOperation(value = "注册")
    @PostMapping("/register")
    public Result<Object> register(@RequestBody @Validated(value = {AddGroup.class}) UserBaseSaveReqVO userBase) {
//        if (baageProperties.getCaptcha()) {
//            this.checkCaptcha(userBase.getUuid(), userBase.getCaptcha());
//        }
        User user = BeanUtil.copyProperties(userBase, User.class);
        authService.register(user);
        return Result.success();
    }


    @ApiOperation(value = "图片获取验证码")
    @GetMapping("/captchaImg")
    public Result<Object> getCode() {
        // 生成验证码，并获取算式和结果
        String capText = captchaProducerMath.createText();
        String capStr = capText.substring(0, capText.lastIndexOf("@"));
        String code = capText.substring(capText.lastIndexOf("@") + 1);
        BufferedImage image = captchaProducerMath.createImage(capStr);
        // 保存验证码信息
        String uuid = IdUtil.simpleUUID();
        String verifyKey = CacheConstant.CAPTCHA_KEY + uuid;
        redisService.set(verifyKey, code, BaageConstant.CAPTCHA_EXPIRATION);
        // 转换流信息写出
        Map<String, Object> resData = new HashMap<>();
        try(
            FastByteArrayOutputStream os = new FastByteArrayOutputStream();
        ){
            ImageIO.write(image, "jpg", os);
            resData.put("uuid", uuid);
            resData.put("img", Base64.encode(os.toByteArray()));
        } catch (IOException e) {
            log.error("验证码生成失败:" + e.getMessage());
            redisService.delete(verifyKey);
            return Result.fail("验证码生成失败");
        }
        return Result.success(resData);
    }


    @ApiOperation(value = "获取邮箱验证码（忘记密码）")
    @PostMapping("/forget/emailCode")
    public Result<Object> getMailCodeForForget(@RequestBody Map<String, String> param) {
        if (param == null || param.get("email") == null) {
            throw new BizException(ExceptionType.PARAM_NOT_VALID);
        }
        // TODO: 验证邮箱格式
        String email = param.get("email");
        String code = CodeUtils.randomCode(6);
        String uuid = IdUtil.simpleUUID();
        String emailBase64 = Base64.encodeUrlSafe(email);
        mailUtils.sendCode(email, code);
        String verifyKey = CacheConstant.MAIL_CODE_KEY + uuid + "-" + emailBase64;
        redisService.set(verifyKey, code, BaageConstant.CAPTCHA_EXPIRATION);
        Map<String, Object> resData = new HashMap<String, Object>() {{
           put("uuid", uuid);
        }};
        return Result.success(resData);
    }


    @ApiOperation(value = "忘记密码-修改密码")
    @PostMapping("/forget")
    public Result<Object> forget(@RequestBody @Validated ForgetReqVO forgetReqVO) {
        String emailBase64 = Base64.encodeUrlSafe(forgetReqVO.getEmail());
        String verifyKey = CacheConstant.MAIL_CODE_KEY + forgetReqVO.getUuid() + "-" + emailBase64;
        String codeByCache = redisService.get(verifyKey);
        if (StrUtil.isBlank(codeByCache) || !codeByCache.equals(forgetReqVO.getCode())) {
            throw new BizException(ExceptionType.CAPTCHA_ERROR);
        }
        authService.forget(forgetReqVO);
        redisService.delete(verifyKey);
        return Result.success();
    }


    @ApiOperation(value = "获取登录信息")
    @GetMapping("/loginInfo")
    public Result<User> loginInfo() {
        User loginUserInfo = userService.getLoginUserInfo();
        return Result.success(loginUserInfo);
    }


    @ApiOperation(value = "更新个人信息")
    @PostMapping("/updateLoginInfo")
    public Result<Object> updateLoginInfo(@RequestBody User user) {
        userService.updateLoginInfo(user);
        return Result.success();
    }


    /**
     * 校验图片验证码
     *
     * @param uuid uuid
     * @param captcha 验证码
     */
    private void checkCaptcha(String uuid, String captcha) {
        if (StrUtil.isBlank(uuid) || StrUtil.isBlank(captcha)) {
            throw new BizException(ExceptionType.PARAM_NOT_VALID);
        }
        String verifyKey = CacheConstant.CAPTCHA_KEY + uuid;
        String verify = redisService.get(verifyKey);
        if (!captcha.equals(verify)) {
            throw new BizException(ExceptionType.CAPTCHA_ERROR);
        }
        redisService.delete(verifyKey);
    }



}
